#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <opencv2/opencv.hpp>
//#include <Eigen/Eigen>
#include "fstream"
const int cubesize = 32;
const int samplesize = 50000;
cv::Mat Wave(cv::Mat& img)
{
     int Height = img.cols;
     int Width = img.rows;
     int depth = 3; //定义分解深度
     int depthcount = 1;
     cv::Mat tmp = cv::Mat::ones(Width, Height, CV_32FC1);
     cv::Mat wavelet = cv::Mat::ones(Width, Height, CV_32FC1);
     cv::Mat imgtmp = img.clone();
     imgtmp.convertTo(imgtmp, CV_32FC1);
     while (depthcount<=depth){
         Width = img.rows / depthcount;
         Height = img.cols / depthcount;
         for (int i = 0; i < Width; i++){
             for (int j = 0; j < Height / 2; j++){
                 tmp.at<float>(i, j) = (imgtmp.at<float>(i, 2 * j) + imgtmp.at<float>(i, 2 * j + 1)) / 2;
                 tmp.at<float>(i, j + Height / 2) = (imgtmp.at<float>(i, 2 * j) - imgtmp.at<float>(i, 2 * j + 1)) / 2;
             }
         }
         for (int i = 0; i < Width / 2; i++){
             for (int j = 0; j < Height; j++){
                 wavelet.at<float>(i, j) = (tmp.at<float>(2 * i, j) + tmp.at<float>(2 * i + 1, j)) / 2;
                 wavelet.at<float>(i + Width / 2, j) = (tmp.at<float>(2 * i, j) - tmp.at<float>(2 * i + 1, j)) / 2;
             }
         }
         imgtmp = wavelet;
         depthcount++;
     }
    // wavelet.convertTo(wavelet, CV_8UC1);
    // wavelet += 50; //图像暗度过低，所以这里我加了50
    // imshow("jpg", wavelet);
     return wavelet;
}
void WaveE(cv::Mat& E)
{
    for(int i=0;i<E.rows;i++){
        if(i%5000==0)
            std::cout<<"waveE"<<i<<std::endl;
        for(int j=0;j<6;j++){
            cv::Mat cur = E.row(i).colRange(32*32*j,32*32*(j+1));
            cur.reshape(0, 32).copyTo(cur);
            Wave(cur).copyTo(cur);
            cur.reshape(0, 1).copyTo(E.row(i).colRange(32*32*j,32*32*(j+1)));
        }
    }
}
void QuaE(cv::Mat &E, std::vector<int> maxid[], cv::Mat& minmax)
{
    cv::Mat ans(E.rows, 128,CV_8UC1);
    for(int id=0;id<E.rows;id++){
        if(id%5000==0)
            std::cout<<"quaE"<<id<<std::endl;
        float* p = E.ptr<float>(id);
        std::vector<int> curvector = maxid[id];
        float min = p[curvector[curvector.size()-1]];
        float max = p[curvector[0]]-p[curvector[curvector.size()-1]];
        minmax.at<float>(id,0) = min;
        minmax.at<float>(id,1) = max;
        cv::Mat Cur = cv::Mat::zeros(1, 128, CV_8UC1);
        std::sort(curvector.begin(), curvector.end());
        uchar* p2 = Cur.ptr<uchar>(0);
        for(int i=0;i<curvector.size();i++){
             p2[i] = (uchar)std::round((p[curvector[i]] )*255+0.5);
        }
        Cur.copyTo(ans.row(id));
    }
    ans.copyTo(E);
}
void Mysort(cv::Mat& E, std::vector<int> maxid[])
{
    for(int id = 0;id<E.rows;id++){
        if(id%5000==0)
            std::cout<<"mysort"<<id<<std::endl;
        for(int i=0;i<128;i++){
            maxid[id].push_back(-1);
        }
        float* p = E.ptr<float>(id);
        for(int j=0;j<E.cols;j++){
            float cur = p[j];//把当前的数拿出来；
            //去找找记录的有没有比它小的
            for(int k=0;k<maxid[id].size();k++){
                //遇到尾部都没找到，而且vector没满，直接放尾部
                if(maxid[id][k]==-1){
                    maxid[id][k] = j;
                    break;
                }
                //如果遇到大的继续下去
                if(p[maxid[id][k]] >= cur)
                    continue;
                //如果遇到小的，直接插进去，删了最后那个
                else if (p[maxid[id][k]] < cur){
                    maxid[id].insert(maxid[id].begin()+k, j);
                    maxid[id].pop_back();
                    break;
                }
            }
        }
    }
}

int main()
{
    //输入E
    std::ifstream in("E.txt", std::ios::binary);
    std::cout<<"open"<<std::endl;
    cv::Mat E(samplesize, cubesize*cubesize*6,CV_32FC1);
    in.read((char*)E.data, E.rows * E.cols * sizeof(float));
    //对E做小波变换
    WaveE(E);
    //只要记录最大的id
    std::cout<<E.row(0)<<std::endl;

    std::vector<int> maxid[50000];
    //去排吧
    Mysort(E, maxid);

    cv::Mat minandmax(50000,2,CV_32FC1);
    QuaE(E, maxid, minandmax);

    //输出那堆大的id
    for(int i=0;i<50000;i++){
        std::sort(maxid[i].begin(), maxid[i].end());
    }
    std::ofstream out2("maxid.txt", std::ios::binary);
    for(int j=0;j<50000;j++){
        std::vector<int> cur = maxid[j];
        for(int i=0;i<cur.size();i++){
            out2.write((char*)&(cur[i]), sizeof(int));
            if(j==0)
                std::cout<<cur[i]<<std::endl;
        }
    }
    std::cout<<"output maxid is finished"<<std::endl;
    //输出小波后的E
    std::ofstream out("waveE.txt",std::ios::binary);
    out.write((char*)E.data, E.rows * E.cols * sizeof(uchar));
    std::cout<<"output fileE is finished"<<std::endl;
    //输出最大最小，用于还原
    std::ofstream out3("minmax.txt",std::ios::binary);
    out3.write((char*)minandmax.data, minandmax.rows * minandmax.cols * sizeof(uchar));
    std::cout<<"output minandmax is finished"<<std::endl;
}
